// ==UserScript==
// @name         拓展-控制台调试-控制台调试更方便
// @version      0.3.6
// @description  拓展-控制台调试-控制台调试更方便, Object | Date | String | Array | Node 对象拓展
// @author       cy2
// @match        *://*/*
// @homepage     https://gitee.com/caiyaoyuan/script-sets/tree/master
// @namespace    https://gitee.com/caiyaoyuan/script-sets/blob/master/JavaScript/ConsoleDevExt.js
// @updateURL    https://gitee.com/caiyaoyuan/script-sets/raw/master/JavaScript/ConsoleDevExt.js
// @downloadURL  https://gitee.com/caiyaoyuan/script-sets/raw/master/JavaScript/ConsoleDevExt.js
// @icon         
// @run-at       document-end
// @grant        none
// ==/UserScript==

(function() {
    'use strict';
    // ----------------------------------------------------

    // Object 在浏览器使用原型拓展会出现各种问题
    Object.isEmpty = function(obj) {
        if (obj == undefined) { // 包含 null 和 undefined
            return true;
        } else if (typeof obj === "string" || Array.isArray(obj)) {
            return obj.length == 0;
        } else {
            return false;
        }
    }

    Object.toHex = function(num = 0){
        return '0x' + num.toString(16);
    }

    Object.randomInt = function(min, max) {
        return Math.floor(Math.random() * (max - min)) + min;
    }

    Object.randomOnce = function(array) {
        let result = null;
        if (array?.length > 0) {
            result = array[Math.floor(Math.random() * array.length)];
        }
        return result;
    }

    Object.guid = function(){
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
            let r = Math.random() * 16 | 0,
                v = c == 'x' ? r : (r & 0x3 | 0x8);
            return v.toString(16);
        });
    }

    Object.uuid = function(){
        let s = [];
        let hexDigits = "0123456789abcdef";
        for (var i = 0; i < 36; i++) {
            s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
        }
        s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
        s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
        s[8] = s[13] = s[18] = s[23] = "-";
        return s.join("");
    }

    Object.ruid = function(len = 16) {
        let ruid= [], chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
        for (let i = 0; i < len; i++) {
            ruid[i] = chars[0 | Math.random() * chars.length];
        }
        return ruid.join('');
    }

    Object.querys = function(uri = location.href){
        let obj = {};
        let url = new URL(uri);
        let arr = url.search.split("&");
        for(let str of arr) {
            let t = str.split("=");
            obj[t[0]] = t[1];
        }
        return obj;
    }

    Object.domUrlJoin = function(nodes, base = location.href, attr = "href", join = "\r\n", println = true){
        let arr = [];
        if(nodes instanceof NodeList || Array.isArray(nodes)){
            nodes.forEach((i, v) => {
                let href = base + i.attr(attr);
                //console.info(v, i instanceof Node, href, v);
                arr.push(href);
            });
            if (println){
                console.info(arr.join(join));
            }
        }
        return arr;
    }

    Object.formatFileSize = function(size) {
		if (!size) {
			return "0K";
		}
		let num = 1024.00; //byte
		if (size < num) {
			return size + "B";
		} else if (size < Math.pow(num, 2)) {
			return (size / num).toFixed(2) + "K"; //kb
		} else if (size < Math.pow(num, 3)) {
			return (size / Math.pow(num, 2)).toFixed(2) + "M"; //M
		} else if (size < Math.pow(num, 4)) {
			return (size / Math.pow(num, 3)).toFixed(2) + "G"; //G
		} else {
			return (size / Math.pow(num, 4)).toFixed(2) + "T"; //T
		}
	}

    // 动态加载JavaScript文件
    Object.loadScript = function(url) {
        let script = document.createElement('script');
        script.type = 'text/javascript';
        script.src = url;
        document.body.appendChild(script);
    }

    // 动态加载CSS样式
    Object.loadStyle = function(url) {
        let style = document.createElement('link');
        style.rel = 'stylesheet';
        style.type = 'text/css';
        style.href = url;
        document.head.appendChild(style);
    }

    // ----------------------------------------------------

    Date.prototype.format = function(fmt = "yyyy-MM-dd HH:mm:ss:S") {
        let opt = {
            "M+" : this.getMonth()+1,                 //月份
            "d+" : this.getDate(),                    //日
            "h+" : this.getHours()%12, 				  //小时   12小时制
            "H+" : this.getHours(),                   //小时   24小时制
            "m+" : this.getMinutes(),                 //分
            "s+" : this.getSeconds(),                 //秒
            "q+" : Math.floor((this.getMonth()+3)/3), //季度
            "S"  : this.getMilliseconds()             //毫秒
        };
        if(/(y+)/.test(fmt)){
            fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length));
        }
        for(let k in opt){
            if(new RegExp("("+ k +")").test(fmt)) {
                fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (opt[k]) : (("00"+ opt[k]).substr((""+ opt[k]).length)));
            }
        }
        return fmt;
    }

    Date.prototype.getShortTime = function (offset = 0){
        return Number.parseInt(this.getTime() / 1000) + offset;
    }

    Date.prototype.isDuringDate = function(beginDateStr, endDateStr) {
        let beginDate = new Date(beginDateStr),
            endDate = new Date(endDateStr);
        if (this >= beginDate && this <= endDate) {
            return true;
        }
        return false;
    }

    // ----------------------------------------------------

    /*文本格式化 支持对象 和 序列顺序*/
    String.prototype.format = function(args) {
        if (arguments.length > 0) {
            let result = this;
            if (arguments.length == 1 && typeof (args) == "object") {
                for ( let key in args) {
                    let reg = new RegExp("({" + key + "})", "g");
                    result = result.replace(reg, args[key]);
                }
            } else {
                for (let i = 0; i < arguments.length; i++) {
                    if (arguments[i] == undefined) {
                        return "";
                    } else {
                        let reg = new RegExp("({[" + i + "]})", "g");
                        result = result.replace(reg, arguments[i]);
                    }
                }
            }
            return result;
        } else {
            return this;
        }
    }

    /** 驼峰命名 小驼峰法(默认'-'转小驼峰) */
    String.prototype.camelize = function (arg) {
        return this.replace(arg ? arg : /-(\w)/g, (_, c) => c ? c.toUpperCase() : '');
    }

    /** 驼峰转'-' */
    String.prototype.capitalize = function() {
        return this.replace(/\B([A-Z])/g, '-$1').toLowerCase();
    }

    // 驼峰命名 大驼峰法（Upper Camel Case）也称为：帕斯卡命名法：（pascal方法）
    String.prototype.pascal = function(){
        return this.replace(/^[a-z]/, (c) => c ? c.toUpperCase() : '').camelize();
    }

    // ----------------------------------------------------
    
    Array.prototype.randomOnce= function() {
        return this[Math.floor(Math.random() * this.length)];
    }

    Array.prototype.randomList = function() {
        for(let j, x, i = this.length; i; j = parseInt(Math.random() * i), x = this[--i], this[i] = this[j], this[j] = x);
        return this;
    }

    Array.prototype.max = function(args) {
        if (this.length == 0) {
            return undefined;
        }
        let result = Math.max.apply(null, this);
        if (isNaN(result)) {
            throw new Error('包含非数字项，无法计算');
        }
        return result;
    }
    Array.prototype.min = function(args) {
        if (this.length == 0) {
            return undefined;
        }
        let result = Math.min.apply(null, this);
        if (isNaN(result)) {
            throw new Error('包含非数字项，无法计算');
        }
        return result;
    }
    Array.prototype.pushAll = function(...arrays){
        if(arrays.length > 0){
            let empty = [];
            for(let array of arrays) {
                empty.push.apply(this, array);
            }
        }
        return this;
    }

    // ----------------------------------------------------

    Node.isNode = function(ele){
        return ele instanceof Node;
    }
    Node.isElement = function(ele){
        return ele instanceof Element;
    }
    Node.isText = function(ele){
        return ele instanceof Text;
    }

    // <this><ele></ele><this>
    Node.prototype.append = function(ele){
        if(ele instanceof Node){
            this.appendChild(ele);
        }
        return this;
    }

    // <ele><this><this></ele>
    Node.prototype.appendTo = function(ele){
        if(ele instanceof Node){
            ele.appendChild(this);
        }
        return this;
    }

    // <this><ele></ele><fec></fec><this>
    Node.prototype.prepend = function(ele){
        if(ele instanceof Node){
            //this.parent;
            let fec = this.firstElementChild;
            if(Node.isNode(fec)){
                this.insertBefore(ele, fec);
            } else {
                this.appendTo(ele);
            }
        }
        return this;
    }

    // <ele><this/><fec/><ele>
    Node.prototype.prependTo = function(ele){
        if(ele instanceof Node){
            let fec = ele.firstElementChild;
            if(fec instanceof Node){
                ele.insertBefore(this, fec);
            } else {
                ele.appendTo(this);
            }
        }
        return this;
    }
    // 默认深度克隆
    Node.prototype.clone = function () {
        return this.cloneNode(true);
    }
    // 移除当前元素
    Node.prototype.remove = function () {
        this.parentNode.removeChild(this);
    }
    Node.prototype.addClass = function (classNames) {
        if (!Object.isEmpty(classNames)) {
            this.classList.add(classNames);
        }
        return this;
    }
    Node.prototype.removeClass = function (classNames) {
        if (!Object.isEmpty(classNames)) {
            this.classList.remove(classNames);
        }
        return this;
    }
    Node.prototype.checkoutEmptyAttrNameError = function (attrName) {
        if (attrName == undefined || typeof attrName !== "string" || attrName == "") {
            throw new Error("attribute 名称为空")
        }
        return this;
    }
    Node.prototype.attr = function (attrName, attrValue) {
        this.checkoutEmptyAttrNameError(attrName);
        return arguments.length > 1 ? (this.setAttribute(attrName, attrValue), this) : this.getAttribute(attrName);
    }
    Node.prototype.attrGas = function (attrName, attrValue) { // get and set
        let _t_ = this.checkoutEmptyAttrNameError(attrName).getAttribute(attrName);
        this.setAttribute(attrName, attrValue);// 直接覆盖，不论何值
        return _t_;
    }
    Node.prototype.attrEdit = function (attrName, callback) {
        this.checkoutEmptyAttrNameError(attrName);
        return (callback && callback.apply(this, [this.attr(attrName), attrName]));
    }
    Node.prototype.html = function (html) {
        return arguments.length >= 1 ? (this.innerHTML = html, this) : this.innerHTML;
    }
    Node.prototype.text = function (text) {
        return arguments.length >= 1 ? (this.innerText = text, this) : this.innerText;
    }
    Node.prototype.val = function (val) {
        return arguments.length >= 1 ? (this.value = val, this) : this.value;
    }
    Node.prototype.delay = function (callback, delay = 500, ...args) {
        if (typeof callback !== "function") {
            throw new Error("未定义处理的触发事件");
        }
        clearTimeout(this.attr("data-delay-pid"));
        let pid = setTimeout(() => { callback.apply(this, args); }, delay);
        this.attr("data-delay-pid", pid);
        return this;
    }
    Node.prototype.trigger = function (name) {
        if (Object.isEmpty(name)) {
            throw new Error("触发事件名为空");
        }
        if (document.all) {
            return this[name]();
        } else {
            let e = new Event(name);
            return this.dispatchEvent(e);
        }
    }
})();